package cn.edu.sjtu;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;

import cn.edu.sjtu.dfa.*;

/**
 * Dealing with Data Flow Analysis, using GraphBuilder to get the predecessors of every instruction node.
 * @author Seabert
 *
 */
public abstract class DataFlowAnalysis {
	protected ArrayList<Instruction> InstrList = null ;
	protected ArrayList<Set<Integer>> gen, kill, in, out ;
	
	public DataFlowAnalysis(List<Instruction> list){
		this.InstrList = (ArrayList<Instruction>) list;
		if(this.InstrList != null){
			gen = new ArrayList<Set<Integer>>();
			kill = new ArrayList<Set<Integer>>();
			in = new ArrayList<Set<Integer>>();
			out = new ArrayList<Set<Integer>>();
			
			for(int i = 0; i<this.InstrList.size(); i++){
				gen.add(i, new TreeSet<Integer>());
				kill.add(i, new TreeSet<Integer>());
				in.add(i, new TreeSet<Integer>());
				out.add(i, new TreeSet<Integer>());
			}
		}
		else{
			System.out.println("Null Instruction List!");
		}
		
	}
	
	protected abstract void calculateIn(int index);
	
	protected abstract void calculateOut(int index);
	
	protected abstract void calculateGen(int index);
	
	protected abstract void calculateKill(int index);
	
	public abstract void Analysis();
	
	public boolean isSetEqual(Set<Integer> set1, Set<Integer> set2){
		boolean isEqual = true;
		Iterator it1 = set1.iterator();
		Iterator it2 = set2.iterator();
		
		while(it1.hasNext() && it2.hasNext()){
			Integer i1 = (Integer) it1.next();
			Integer i2 = (Integer) it2.next();
			if(!i1.equals(i2)){
				isEqual = false;
				break;
			}
		}
		if(it1.hasNext() || it2.hasNext()){
			isEqual = false;
		}
		
		return isEqual;
	}
			
			
	private void printSets(ArrayList<Set<Integer>> sets){
		Iterator it = sets.iterator();
		int index = 0;
		while(it.hasNext()){
			System.out.print(index++);
			System.out.print(" : ");
			Set<Integer> set = (Set<Integer>) it.next();
			Iterator setIt = set.iterator();
			while(setIt.hasNext()){
				System.out.print(setIt.next());
				System.out.print(", ");
			}
			System.out.println();
		}
		System.out.println("+++++++++++++++SET PRINT DONE++++++++++++++++++++");
	}

	

	public ArrayList<Instruction> getInstrList() {
		return InstrList;
	}

	public void setInstrList(ArrayList<Instruction> instrList) {
		InstrList = instrList;
	}

	
	

	
}
